﻿#include "SrDemux.h"

#include "base/TraceLog.h"

#include <qDebug>

static double r2d(AVRational r)
{
    return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
}

SrDemux::SrDemux()
    :_pFormatCtx(NULL)
    ,_audioStreamIndex(0)
    ,_videoStreamIndex(0)
    ,_width(0)
    ,_height(0)
{
    avformat_network_init();
    av_log_set_level(AV_LOG_INFO); //Set log level (What FFMPEG prints on screen)

}

SrDemux::~SrDemux()
{
    if (_pFormatCtx)
        {
            avformat_close_input(&_pFormatCtx);
            _pFormatCtx = NULL;
        }
}
bool SrDemux::IsAudio(AVPacket *pkt)
{
	if (!pkt) return false;
	if (pkt->stream_index == _videoStreamIndex)
		return false;
	return true;
}

bool SrDemux::Open(const char *url)
{
    LogINFO("[%p] Call %s Start.",this,__FUNCTION__);
    //打开播放
    int ret = avformat_open_input(
                &_pFormatCtx
                , url
                , NULL // NULL表示自动选择解封装器
                ,NULL);
    if (ret != 0)
    {
         char buflog[1024] = { 0 };
         av_strerror(ret, buflog, sizeof(buflog) - 1);
         LogINFO("open url(%s) failed : %s", url, buflog);
         return false;
    }

    //获取流信息
    ret = avformat_find_stream_info(_pFormatCtx, NULL);

    LogINFO("[%p] av_dump_format......", this);
        // Output the stream info to standard
    av_dump_format(_pFormatCtx, 0, NULL, 0);


    // 获取视频流
    _videoStreamIndex = av_find_best_stream(_pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

    AVStream *vs = _pFormatCtx->streams[_videoStreamIndex];
    _width = vs->codecpar->width;
    _height = vs->codecpar->height;
    qDebug("_width = %d _height = %d \n",_width, _height);

    _audioStreamIndex = av_find_best_stream(_pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);

    AVStream *as = _pFormatCtx->streams[_audioStreamIndex];
    _sampleRate = as->codecpar->sample_rate;
     _channels = as->codecpar->channels;


    LogINFO("[%p] Call %s End.",this,__FUNCTION__);
    return true;
}
void SrDemux::Close()
{
    if(_pFormatCtx)
    {
        avformat_close_input(&_pFormatCtx);
        _pFormatCtx = NULL;
    }

}

AVCodecParameters *SrDemux::CopyVPara()
{
    if (!_pFormatCtx)
        {
            return NULL;
        }
        AVCodecParameters *pa = avcodec_parameters_alloc();
        avcodec_parameters_copy(pa, _pFormatCtx->streams[_videoStreamIndex]->codecpar);
        return pa;
}

AVCodecParameters *SrDemux::CopyAPara()
{
       if (!_pFormatCtx)
       {
          return NULL;
       }
       AVCodecParameters *pa = avcodec_parameters_alloc();
       avcodec_parameters_copy(pa, _pFormatCtx->streams[_audioStreamIndex]->codecpar);
       return pa;
}
//pos 0.0 ~ 1.0
bool SrDemux::Seek(double pos)
{
	if (NULL == _pFormatCtx)
	{
		return false;
	}

	//清理读取缓冲
	avformat_flush(_pFormatCtx);

	long long seekPos = _pFormatCtx->streams[_videoStreamIndex]->duration * pos;

	int ret = av_seek_frame(_pFormatCtx, _videoStreamIndex, seekPos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME); // AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME  从后面开始查找出关键帧)
	if (ret < 0)
	{
		return false;
	}

	return true;
}

AVPacket* SrDemux::Read()
{
    if(NULL == _pFormatCtx)
    {
        qDebug("_pFormatCtx is NULL\n");
        return NULL;
    }

    AVPacket * pkt = av_packet_alloc();

    int ret = av_read_frame(_pFormatCtx, pkt);

    if(ret != 0)
    {
        qDebug("av_read_frame != 0\n");
        av_packet_free(&pkt);
        return NULL;
    }

    printf("pkt->stream_index = %d\n",pkt->stream_index);
    //时间换算 毫秒
    pkt->pts = pkt->pts * (r2d(_pFormatCtx->streams[pkt->stream_index]->time_base) * 1000);
    pkt->dts = pkt->dts * (r2d(_pFormatCtx->streams[pkt->stream_index]->time_base) * 1000);


    return pkt;
}
